qx.Class.define("lastfmbackup.test.model.Sync", {
  
  extend : qx.dev.unit.TestCase,

  members : {
    
    testee : null,
    
    
    setUp : function()
    {
      var fetchModel = new lastfmbackup.test.mock.RecentTracksModel();
      fetchModel.setUsername("somebody");
      
      var storageModel = new lastfmbackup.model.Storage();
      storageModel.setUsername("somebody");
      storageModel.resetData();
      
      this.testee = new lastfmbackup.model.Sync();
      this.testee.setFetchModel(fetchModel);
      this.testee.setStorageModel(storageModel);
    },
    
    testRun : function()
    {
      this.testee.getStorageModel().addListenerOnce("save", function()
      {
        this.testee.addListener("prepared", this.testee.run, this.testee);
        this.testee.addListener("complete", function()
        {
          this.resume(function()
          {
            var actual = this.testee.getStorageModel().getStats();
        
            this.assert(Date.now() - actual.lastRun < 128);
            delete actual.lastRun;
            
            this.assertJsonEquals({
              "firstScrobble"     : 1357835873000,
              "lastScrobble"      : 1359209542000,
              "scrobbles"         : 7,
              "storageUsed"       : 1036,
              "formatVersion"     : qx.core.Environment.get("lastfmbackup.version"),
              "rowsetChunkLength" : 2
            }, actual);
          }, this);
        }, this);
        
        var expectedProgress = [].concat(
          Array.range(4).map(function(i)
          {
            return i / 3;
          }),
          Array.range(5).map(function(i)
          {
            return i / 4;
          })
        );
        this.testee.addListener("changeProgress", function(event)
        {
          this.assertEquals(expectedProgress.shift(), event.getData());
        }, this);
        
        var expectedProgressTypes = ["load", "save"];
        this.testee.addListener("changeProgressType", function(event)
        {
          this.assertEquals(expectedProgressTypes.shift(), event.getData());
        }, this);
        
        this.testee.prepare();        
      }, this);
      this.testee.getStorageModel().saveData(lastfmbackup.test.mock.RecentTracksModel.data.slice(5, 7));
      this.wait(10000);
    },
    
    testRunFail : function()
    {
      var message = "Error: Nothing to load, was model prepared?";
      this.assertException(this.testee.run.bind(this.testee), Error, message);
      
      this.testee.getFetchModel().setFail(true);
      this.testee.addListener("prepared", this.testee.run, this.testee);
      this.testee.addListener("abort", function(event)
      {
        this.resume(function()
        {
          this.assertEquals("abort", event.getType());
        }, this);
      }, this);
      this.testee.prepare();
      this.wait();
    },
    
    testPrepare : function()
    {
      this.testee.getStorageModel().addListenerOnce("save", function()
      {
        this.testee.addListener("prepared", function(event)
        {
          this.resume(function()
          {
            this.assertEquals(5, event.getData());
            
            var actual = this.testee.getStorageModel().getStats();
        
            this.assert(Date.now() - actual.lastRun < 500);
            delete actual.lastRun;
            
            this.assertJsonEquals({
              "firstScrobble"     : 1357835873000,
              "lastScrobble"      : 1358333559000,
              "scrobbles"         : 2,
              "storageUsed"       : 364,
              "formatVersion"     : qx.core.Environment.get("lastfmbackup.version"),
              "rowsetChunkLength" : 1
            }, actual);
          }, this);
        }, this);
        
        this.testee.prepare();      
      
      }, this);
      this.testee.getStorageModel().saveData(lastfmbackup.test.mock.RecentTracksModel.data.slice(5, 7));
      this.wait();
    },
    
    testPrepareFail : function()
    {
      this.testee.getFetchModel().setFail(true);
      this.testee.addListener("abort", function(event)
      {
        this.resume(function()
        {
          this.assertEquals("abort", event.getType());
        }, this);
      }, this);
      this.testee.prepare();
      this.wait();
    },
    
    testAbort : function()
    {
      this.testee.addListener("prepared", function()
      {
        this.testee.getFetchModel().setFail(true);
        this.testee.run();
      }, this);
      this.testee.addListener("abort", function(event)
      {
        this.resume(function()
        {
          this.assertEquals("abort", event.getType());
        }, this);
      }, this);
      
      this.testee.prepare();
      qx.event.Timer.once(this.testee.abort, this.testee, 250);
      
      this.wait();
    }
  
  }
    
});